// compile: g++ -o variant variant.cc -std=c++17
// run: ./variant
#include <cassert>
#include <iostream>
#include <variant>
using namespace std;

void Test1() {
  std::variant<int, double> v, w;
  v = 42;  // v contains int
  int i = std::get<int>(v);
  assert(42 == i);  // succeeds
  w = std::get<int>(v);
  w = std::get<0>(v);  // same effect as the previous line
  w = v;               // same effect as the previous line
  cout << v.index() << endl;
  cout << std::get<0>(v) << endl;
  v = 8.43;
  cout << v.index() << endl;
  // cout << std::get<0>(v) << endl;
  // libc++abi: terminating with uncaught exception of type
  // std::bad_variant_access: bad_variant_access
  cout << std::get<1>(v) << endl;

  //  std::get<double>(v); // error: no double in [int, float]
  //  std::get<3>(v);      // error: valid index values are 0 and 1

  try {
    std::get<double>(w);  // w contains int, not float: will throw
  } catch (const std::bad_variant_access& ex) {
    std::cout << ex.what() << '\n';
  }

  using namespace std::literals;

  std::variant<std::string> x("abc");
  // converting constructors work when unambiguous
  x = "def";  // converting assignment also works when unambiguous

  std::variant<std::string, void const*> y("abc");
  // casts to void const * when passed a char const *
  assert(std::holds_alternative<void const*>(y));  // succeeds
  y = "xyz"s;
  assert(std::holds_alternative<std::string>(y));  // succeeds
}
void Test2() {}
int main() {
  Test1();
  Test2();
  return 0;
}
